#! /usr/local/bin/perl

###################################################################
# This program converts the ptm model file to the format that
# Spectre can simulate.
#
# 03/25/2006
#    1. add diffusion area and perimeter parameters
# 03/15/2006
#   1. define PFET/NFET subcircuit with width and length variations
# 03/13/2006
#   1. change to pure Spectre format (remove parenthesis and replace 
#      '.model' with 'model')
#   2. change vth0 expression to include variation
# 02/20/2006
#   1. support BSIM4 models
#   2. support the files that contain both nmos and pmos model 
#   3. add "type = n/p"
###################################################################

print "Enter the PTM model file name (i.e. ptm.txt):";
$PTM_file = <STDIN>;
open (PTM_file, "$PTM_file") or die "Can't find the PTM file."; 
print "Enter the SPECTRE model file name (i.e. 100nm.scs):";
$SPECTRE_file = <STDIN>;
open (TEMP_file, ">TEMP_file") or die "Can't write to TEMP file."; 

# Count the number of the models in the file
$CNT = 0;

while ($line = <PTM_file>) {
  
  # REMOVE THE BLANK LINES AND LEVEL NUMBER
  # I assume that all the valid lines start with *,., or +. 
  if (not($line =~ /^[\*\.\+]/)) {next;}

  # SET BSIM3v3 or BSIM4 ACCORDING TO LEVLE NUMBER
  # ADD BSIM VERSION AND DEFINE THE TRANSISTOR TYPE 
  elsif ($line =~ /^\.model/) { 
    @ModelArrsplit = split(" ", $line, 3);
    if ($ModelArrsplit[1] =~ /^(NMOS)$/i) { 
      $Xtor_type = "type = n"; 
      $FET = "NFET";
    } else { 
      $Xtor_type = "type = p";
      $FET = "PFET"; 
    }

    # Add 'inline subckt NFET/PFET ...' statements 
    #  as well as the default parameter (defw, defl), 
    #  variation parameter (vw, vl) for width and length
    #  and the diffusion area
    print TEMP_file "inline subckt $FET (D G S B)\n";
    print TEMP_file "parameters w=defw l=defl as=(defw*r*defl) ad=(defw*r*defl)\n";
    print TEMP_file "+ ps=2*(defw+r*defl) pd=2*(defw+r*defl)\n";
    print TEMP_file "$FET (D G S B) $ModelArrsplit[1] w=(w+vw) l=(l+vl)\n";
    print TEMP_file "+ as=(w+vw)*r*(l+vl) ad=(w+vw)*r*(l+vl)\n";
    print TEMP_file "+ ps=2*(w+vw+r*(l+vl)) pd=2*(w+vw+r*(l+vl))\n";

    # If level number is in the same line with '.model'
    if ($line =~ /Level/i) {
      if ($line =~ /Level *= *54/i) {
        $BSIM_version = "bsim4";
      } else {
        $BSIM_version = "bsim3v3"; 
      }
      $ModelArrsplit[2] = $BSIM_version;
      $ModelArrsplit[0] = "model";
      print TEMP_file "@ModelArrsplit\n"; 
    }

    $CNT++;
  }
  
  # If level number is in the different line with '.model'
  elsif ($line =~ /^\+Level/i) {
    @Arrsplit = split(" ", $line);
    if ($line =~ /Level *= *54/i) {
      $BSIM_version = "bsim4"; 
    } else {
      $BSIM_version = "bsim3v3";
    }
    $ModelArrsplit[2] = $BSIM_version;
    $ModelArrsplit[0] = "model";
    print TEMP_file "@ModelArrsplit\n";
    # print the rest of the parameters in this line
    $Arrsplit[0] = "";
    $Arrsplit[1] = "";
    $Arrsplit[2] = "";
    print TEMP_file "@Arrsplit\n";
  } 
  
  # ADD "TYPE = N/P" AND REPLACE TREF WITH TNOM
  elsif (($line =~ s/Tref/Tnom/) or ($line =~ /Tnom/i)) {
    @Arrsplit = split(" ", $line);
    $Arrsize = @Arrsplit; 
    @Arrsplit[$Arrsize] = $Xtor_type; 
    print TEMP_file "@Arrsplit\n"; 
  }


  # Change Vth0 expression to include variation
  elsif ($line =~ /^\+vth0/i) { 
    @Arrsplit = split(" ", $line);
    if ($CNT == 1) {
      $VTH0n = @Arrsplit[2];
      @Arrsplit[2] = "(vth0n*vthn_ratio+vvthn)";
    } else {
      $VTH0p = @Arrsplit[2];
      @Arrsplit[2] = "(vth0p*vthp_ratio+vvthp)";
    }
    print TEMP_file "@Arrsplit\n";
  }


  else {
    @Arrsplit = split(" ", $line);
    print TEMP_file "@Arrsplit\n"; 
  }

}

close(TEMP_file); open (TEMP_file, "TEMP_file");
open (SPECTRE_file, ">$SPECTRE_file") or die;
@TEMP_lines = <TEMP_file>;

# Add 'ends PFET/NFET' statement at the end of the model
if ($CNT==1) {
  $TEMP_lines[$#TEMP_lines] .= "ends NFET\n";
} else {
  for ($i=$#TEMP_lines; $i!=-1; $i--) {
    if ($TEMP_lines[$i] =~ /^\inline/) {
      $PMOS_FstLineIndex = $i; 
      last;
    }
  }
  for ($i=$PMOS_FstLineIndex-1; $i!=-1; $i--) {
    if ($TEMP_lines[$i] =~ /^\+/) {
       #chomp($TEMP_lines[$i]);
       $TEMP_lines[$i] .= "ends NFET\n\n\n";
       last; 
    }
  }
  $TEMP_lines[$#TEMP_lines] .= "ends PFET\n";
}

print SPECTRE_file 'simulator lang=spectre', "\n\n";
print SPECTRE_file "parameters vth0n=$VTH0n vth0p=$VTH0p\n";
print SPECTRE_file "parameters vvthn=0 vvthp=0\n";
print SPECTRE_file "parameters vl=0 vw=0\n";
print SPECTRE_file "parameters r=1.5\n\n";
print SPECTRE_file @TEMP_lines;






